#coding=utf-8
'''
author : QyLey
'''
import os, re
import sys
import math
from tkinter import *

class painter(object):
    def find_len(self, content):
        h = 1
        l = [10]
        li = list(content.keys())
        for v in li:
            h = h + 1
            if v[0] == '_':
                lv = 1
            else:
                lv = len(v)+2
            lli = list(content[v].keys())
            for m in lli:
                h = h + 1
                l.append(lv+len(m)+1)
        return h, max(l)


    def __init__(self):
        self.root = Tk()
        self.root.geometry('960x640')
        self.root.title("module_snapshot")
        self.txt=Text(self.root)
        help_info = '''//put your verilog code of module declaration in this text box.
//add lables can make your layout more reasonable:
//<a> xxx </a>: xxx can be the short name or version or else of your module
//</left> : signals after this lable will be moved to left side 
//</right> : signals after this lable will be moved to right side 
        '''
        self.txt.insert(END,help_info)
        self.txt.place(rely=0.0, relx=0.00, relheight=0.95, relwidth=1.0)
        self.btn = Button(self.root, text='generate', command=self.run)
        self.btn.place(relx=0.4, rely=0.95, relwidth=0.2, relheight=0.05)
        self.root.mainloop()
        
    def read_line(self, s):
        patt1=re.compile("^\s+")
        ln=re.sub(patt1,"",s)
        t = None
        sig = []
        mname = ""
        #state 1
        divided = re.split(r"[>[\s]",ln,1)
        start_word = divided[0]
        
        if start_word == 'input':
            t = "signal"
            sig_io = 'input'
            ln = divided[1]
        elif start_word == 'output':
            t = "signal"
            sig_io = 'output'
            ln = divided[1]
        elif start_word == 'inout':
            t = "signal"
            sig_io = 'inout'
            ln = divided[1]
        elif start_word == 'module':
            t = "module"
            ln = divided[1]
        elif start_word == '</left':
            t = "left"
        elif start_word == '</right':
            t = "right"
        elif start_word == '<a':
            t = "abbr"
            ln = divided[1]

        #state 2
        ln=re.sub(patt1,"",ln)
        if t == 'signal':
            ssss=re.search('^\[.*:.*\]?',ln)
            if ssss:
                higher = re.search('^\[.*?:',ssss.group()).group()
                lower = re.search(':.*?\]',ssss.group()).group()
                try:
                    sig_wid = int(eval(higher[1:-1] + '-' + lower[1:-1] + '+1'))
                except:
                    sig_wid = higher[1:-1]
                divided = re.split(r"[,\s]",ln,1)
                ln = divided[1]
            else:
                sig_wid = '1'
        elif t == 'module':
            divided = re.split(r"[#\(\s]",ln,1)
            mname = divided[0]
        elif t == 'abbr':
            divided = re.split(r"\s*</a>",ln,1)
            mname = divided[0]
            
        #stage 3
        ln=re.sub(patt1,"",ln)
        if t == 'signal':
            divided = re.split(r"[,\s]",ln,1)
            sig_name = divided[0]
            sig = [sig_name, sig_io, sig_wid]
        return [t, sig, mname]
    
    def run(self):
        module_declaration = self.txt.get(0.0,END)
        md_lines = re.split(r"[\n]",module_declaration)
        
        
        right = 0
        i = 0
        t_last = None
        self.name = ""
        self.abbr = ""
        self.left = {}
        self.right = {}
        for ln in md_lines:
            [t, sig, mname] = self.read_line(ln)
            if t == 'module':
                self.name = mname
            elif t == 'abbr':
                self.abbr = mname
            elif t == 'signal':
                if t_last != 'signal':
                    i = i+1
                kk = "_"+str(i)
                if right:
                    if kk not in self.right.keys():
                        self.right[kk] = {}
                    self.right[kk][sig[0]] = [sig[1],sig[2]]
                else:
                    if kk not in self.left.keys():
                        self.left[kk] = {}
                    self.left[kk][sig[0]] = [sig[1],sig[2]]
            elif t == 'left':
                right = 0
            elif t == 'right':
                right = 1
            
            t_last = t
            
            

        self.hl, self.ll = self.find_len(self.left)
        self.hr, self.lr = self.find_len(self.right)
        
        self.draw()
        
        return
        
    def draw(self):
        winNew = Toplevel(self.root)
        winNew.title("module_snapshot")
        border_x = 100
        border_y = 20
        line_x = 13
        line_y = 28
        ctr_maxwidth = 10
        
        sss = re.split(r"[_]",self.name)
        title = sss[0]
        i = len(sss[0])
        
        for s in sss[1:]:
            if i < ctr_maxwidth and len(s)<ctr_maxwidth/2:
                title = title + '_' + s
                i = i+len(s)+1
            else:
                title = title + '\n_' + s
                i = len(s)+1
        if self.abbr:
            title = title + '\n(' + self.abbr + ')'
        title_ln = re.split(r"[\n]",title)
        ln_num = len(title_ln)-1
        
        line_mid = 0
        for t in title_ln:
            if(len(t)>line_mid):
                line_mid = len(t)
        height = line_y*max(self.hl, self.hr)
        width = line_x*(2*max(self.ll,self.lr)+line_mid+2)
        
        self.cv = Canvas(winNew,bg = 'white', height = height+border_y*2, width = width+border_x*2)
        self.cv.create_rectangle(border_x,border_y,width+border_x,height+border_y, fill = 'white', width = 2)
        
        start_y = (height+border_y*2-ln_num*line_y)/2
        i = 0
        for s in title_ln:
            self.cv.create_text(border_x+width/2,start_y + i*line_y,text=s,fill ='#808080',anchor = "c",font=('Courier', 15, 'bold'))
            i=i+1
        
        i = 1
        start_y = (height+border_y*2-(self.hl-1)*line_y)/2
        li = list(self.left.keys())
        for d in li:
            lli = list(self.left[d].keys())
            if d[0]=='_':
                signal_part = ''
            else:
                signal_part = d + '_'
            for s in self.left[d]:
                if self.left[d][s][0]=='input':
                    x0 = border_x+16
                    y0 = start_y+i*line_y
                    x1 = border_x+4
                    y1 = start_y+i*line_y-6
                    x2 = border_x+4
                    y2 = start_y+i*line_y+6
                    self.cv.create_polygon(x0, y0, x1, y1, x2, y2,fill ='#c0c0c0')
                elif self.left[d][s][0]=='output':
                    x0 = border_x+4
                    y0 = start_y+i*line_y
                    x1 = border_x+16
                    y1 = start_y+i*line_y-6
                    x2 = border_x+16
                    y2 = start_y+i*line_y+6
                    self.cv.create_polygon(x0, y0, x1, y1, x2, y2,fill ='#c0c0c0')
                else:
                    x0 = border_x+17
                    y0 = start_y+i*line_y
                    x1 = border_x+11
                    y1 = start_y+i*line_y-6
                    x2 = border_x+11
                    y2 = start_y+i*line_y+6
                    self.cv.create_polygon(x0, y0, x1, y1, x2, y2,fill ='#c0c0c0')
                    x0 = border_x+3
                    y0 = start_y+i*line_y
                    x1 = border_x+9
                    y1 = start_y+i*line_y-6
                    x2 = border_x+9
                    y2 = start_y+i*line_y+6
                    self.cv.create_polygon(x0, y0, x1, y1, x2, y2,fill ='#c0c0c0')
                signal_width = self.left[d][s][1]
                signal_name = signal_part + s
                self.cv.create_text(border_x+20,start_y + i*line_y,text=signal_name,fill ='#000000',anchor = "w",font=('Courier', 15))
                if signal_width == '1':
                    self.cv.create_line(10,start_y + i*line_y,border_x,start_y + i*line_y,width=2)
                else:
                    self.cv.create_line(10,start_y + i*line_y,border_x,start_y + i*line_y,width=4)
                    self.cv.create_line(20,start_y + i*line_y-5,30,start_y + i*line_y+5,width=2)
                    self.cv.create_text(30,start_y + i*line_y-10,text=signal_width,fill ='#000000',anchor = "w",font=('Courier', 12))
                i = i+1
            i=i+1
               

        i = 1
        start_y = (height+border_y*2-(self.hr-1)*line_y)/2
        li = list(self.right.keys())
        for d in li:
            lli = list(self.right[d].keys())
            if d[0]=='_':
                signal_part = ''
            else:
                signal_part = d + '_'
            for s in self.right[d]:
                signal_width = self.right[d][s][1]
                signal_name = signal_part + s
                self.cv.create_text(width+border_x-20,start_y + i*line_y,text=signal_name,fill ='#000000',anchor = "e",font=('Courier', 15))
                if self.right[d][s][0]=='input':
                        x0 = width+border_x-16
                        y0 = start_y+i*line_y
                        x1 = width+border_x-4
                        y1 = start_y+i*line_y-6
                        x2 = width+border_x-4
                        y2 = start_y+i*line_y+6
                        self.cv.create_polygon(x0, y0, x1, y1, x2, y2,fill ='#c0c0c0')
                elif self.right[d][s][0]=='output':
                    x0 = width+border_x-4
                    y0 = start_y+i*line_y
                    x1 = width+border_x-16
                    y1 = start_y+i*line_y-6
                    x2 = width+border_x-16
                    y2 = start_y+i*line_y+6
                    self.cv.create_polygon(x0, y0, x1, y1, x2, y2,fill ='#c0c0c0')
                else:
                    x0 = width+border_x-17
                    y0 = start_y+i*line_y
                    x1 = width+border_x-11
                    y1 = start_y+i*line_y-6
                    x2 = width+border_x-11
                    y2 = start_y+i*line_y+6
                    self.cv.create_polygon(x0, y0, x1, y1, x2, y2,fill ='#c0c0c0')
                    x0 = width+border_x-3
                    y0 = start_y+i*line_y
                    x1 = width+border_x-9
                    y1 = start_y+i*line_y-6
                    x2 = width+border_x-9
                    y2 = start_y+i*line_y+6
                    self.cv.create_polygon(x0, y0, x1, y1, x2, y2,fill ='#c0c0c0')
                if signal_width == '1':
                    self.cv.create_line(width+2*border_x-10,start_y + i*line_y,width+border_x,start_y + i*line_y,width=2)
                else:
                    self.cv.create_line(width+2*border_x-10,start_y + i*line_y,width+border_x,start_y + i*line_y,width=4)
                    self.cv.create_line(width+border_x+20,start_y + i*line_y-5,width+border_x+30,start_y + i*line_y+5,width=2)
                    self.cv.create_text(width+border_x+30,start_y + i*line_y-10,text=signal_width,fill ='#000000',anchor = "w",font=('Courier', 12))   
                i = i+1
            i=i+1
        
        self.cv.pack()
        #self.cv.postscript(file="a.ps", colormode='color')
        self.root.update()
        return


g = painter()
#g.draw()
